/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2014-06-12
 * V4.0
 */
package com.jphenix.share.lang;

import com.jphenix.standard.db.IBuffer;
import com.jphenix.standard.docs.ClassInfo;

import java.util.ArrayList;
import java.util.Collection;

/**
 * 快速缓存
 * 
 * 内部有两个缓存对象，A缓存输入时，B缓存在输出
 * 
 * B缓存输出并处理完毕后，执行切换方法，由B缓存输入，A缓存输出
 * 
 * 注意：该类不能用在输入效率大于输出效率情况，这样会导致缓存中的数据越来越大，最后内存溢出
 * 
 * 通常用在连续输入，成批处理的地方
 * 
 * 2018-09-25 增加了toString发方法
 * 
 * @author 刘虻
 * 2012-11-15 上午8:58:54
 */
@ClassInfo({"2018-09-25 18:16","快速缓存"})
public class SFastBuffer implements IBuffer {

	protected ArrayList<Object> 
							 bufferA = new ArrayList<Object>()		//缓存A
						    ,bufferB = new ArrayList<Object>();		//缓存B
	
	protected int  index = 0;								//缓存索引
	
	protected int maxElementCount = 102400; //缓存中最大元素总数 默认为1M
	
	protected boolean isInputA = true; //缓存A是否为输入缓存
	
	/**
	 * 构造函数
	 * @author 刘虻
	 */
	public SFastBuffer() {
		super();
	}
	
	/**
	 * 构造函数
	 * @author 刘虻
	 * @param maxElementCount 缓存中最大元素总数 默认为1M
	 */
	public SFastBuffer(int maxElementCount) {
		super();
		this.maxElementCount = maxElementCount;
	}

	/**
	 * 清除缓存中的内容
	 * 刘虻
	 * 2012-11-15 上午9:22:53
	 */
	@Override
    public void clear() {
		bufferA.clear();
		bufferB.clear();
	}
	
	/**
	 * 切换缓存
	 * 刘虻
	 * 2012-11-15 上午9:39:37
	 */
	public synchronized void  switchBuffer() {
		isInputA = !isInputA;
		if(isInputA) {
			bufferA = new ArrayList<Object>();
		}else {
			bufferB = new ArrayList<Object>();
		}
		index = 0;
	}
	
	
	/**
	 * 将指定值放入缓存中
	 * 刘虻
	 * 2012-11-15 上午9:57:27
	 * @param obj 指定值
	 */
	@Override
    public void add(Object obj) {
		//先判断当前缓存是否达到上限，如果已经达到上限，先等待切换缓存
		if(isInputA) {
			if(bufferA.size()>maxElementCount) {
				while(isInputA) {
					try {
						Thread.sleep(100);
					}catch(Exception e) {
						e.printStackTrace();
						break;
					}
				}
				bufferB.add(obj);
			}else {
				bufferA.add(obj);
			}
		}else {
			if(bufferB.size()>maxElementCount) {
				while(!isInputA) {
					try {
						Thread.sleep(100);
					}catch(Exception e) {
						e.printStackTrace();
						break;
					}
				}
				bufferA.add(obj);
			}else {
				bufferB.add(obj);
			}
		}
	}
	
	/**
	 * 获取其中一个缓存中的值
	 * 主动调用switchBuffer方法切换两个缓存时调用的方法
	 * 刘虻
	 * 2012-11-15 上午9:55:43
	 * @return 缓存中的值
	 */
	@Override
    public Object get() {
		if(isInputA) {
			if(bufferB.size()>index) {
				return bufferB.get(index++);
			}
		}else {
			if(bufferA.size()>index) {
				return bufferA.get(index++);
			}
		}
		return null;
	}
	
	/**
	 * 获取当前输出缓存大小
	 * @return 当前输出缓存大小
	 * 刘虻
	 * 2012-11-16 下午6:31:22
	 */
	@Override
    public int size() {
		if(isInputA) {
			return bufferB.size()-index;
		}else {
			return bufferA.size()-index;
		}
	}

	/**
	 * 覆盖方法
	 * 刘虻
	 * 2012-11-18 下午2:35:54
	 */
	@Override
    public void addAll(Collection<?> c) {
		//先判断当前缓存是否达到上限，如果已经达到上限，先等待切换缓存
		if(isInputA) {
			if(bufferA.size()>maxElementCount) {
				while(isInputA) {
					try {
						Thread.sleep(100);
					}catch(Exception e) {
						e.printStackTrace();
						break;
					}
				}
				bufferB.addAll(c);
			}else {
				bufferA.addAll(c);
			}
		}else {
			if(bufferB.size()>maxElementCount) {
				while(!isInputA) {
					try {
						Thread.sleep(100);
					}catch(Exception e) {
						e.printStackTrace();
						break;
					}
				}
				bufferA.addAll(c);
			}else {
				bufferB.addAll(c);
			}
		}
	}

	/**
	 * 覆盖方法
	 * 刘虻
	 * 2012-11-18 下午5:45:05
	 */
	@Override
    public boolean contains(Object obj) {
		if(isInputA) {
			return bufferB.contains(obj);
		}
		return bufferA.contains(obj);
	}

	/**
	 * 覆盖方法
	 * 刘虻
	 * 2013-1-22 下午1:22:30
	 */
	@Override
    public void addFirst(Object obj) {
		//先判断当前缓存是否达到上限，如果已经达到上限，先等待切换缓存
		if(isInputA) {
			if(bufferA.size()>maxElementCount) {
				while(isInputA) {
					try {
						Thread.sleep(100);
					}catch(Exception e) {
						e.printStackTrace();
						break;
					}
				}
				bufferB.add(0,obj);
			}else {
				bufferA.add(0,obj);
			}
		}else {
			if(bufferB.size()>maxElementCount) {
				while(!isInputA) {
					try {
						Thread.sleep(100);
					}catch(Exception e) {
						e.printStackTrace();
						break;
					}
				}
				bufferA.add(0,obj);
			}else {
				bufferB.add(0,obj);
			}
		}
	}
	
	/**
	 * 覆盖方法
	 */
	@Override
    public String toString() {
		return "SFastBuffer:\nindex:["+index+"]\nisInputA:["+isInputA+"]\nmaxElementCount:["
					+maxElementCount+"]\nbufferASize:["+bufferA.size()+"]\nbufferBSize:["
				+bufferB.size()+"]\nbufferA:\n"+bufferA+"\n\nbufferB:\n"+bufferB;
	}
}
